﻿#pragma once

#include "Containers/Optional.h"
#include "Containers/Map.h"
#include "Containers/String.h"

#include "TypeTable.h"
#include "TypeID.h"

class CFunction;
class CFunctionList;
class CProperty;
class CNativeFieldProperty;
class CPropertyList;
class CGenericInfo;
class CGeneralizedInfo;
//class CNameScope;
class IStringSerializable;
class ITypeInstance;
class CPlaceholderInfo;
class IGarbageCollectable;

enum class ETypeFlags : uint32_t 
{
    None=0, //impossible flag
    Script=1<<0, //type is not defined in c++
                 //such as TMap<int,AScriptClass> is script type
    Basic=1<<1, //type is basic type. such as int32_t , float ,bool,CString, etc.
    Class=1<<2, //type is class type. such as RObject, RWidget, etc.
    Struct=1<<3, //type is struct type. such as SVector3, SVector4, etc.
    Enum=1<<4, //type is enum type. such as EInputEvent, etc.
    Generic=1<<5, //type is generic type. such as TVector<T>, TPair<T1,T2>, etc.
    Generalized=1<<6, //type is generalized type. such as TVector<int>, TPair<int,float>, etc.
    Placeholder=1<<7, //type is generic placeholder type. such as T, T1, T2, etc.
    SharedObjectPtr=1<<8, //type is shared object pointer type. such as TSharedObjectPtr<RObject>, TSharedObjectPtr<RWidget>, etc.
    WeakObjectPtr=1<<9, //type is weak object pointer type. such as TWeakObjectPtr<RObject>, TWeakObjectPtr<RWidget>, etc.
    RawPointer=1<<10, //type is raw pointer type. such as RObject*,TWeakObjectPtr<RObject>* ,int*, etc.
    FunctionPointer=1<<11, //type is function pointer type. this type's value is CFunction
    Delegate=1<<12, //type is delegate type. such as TDelegate<void()> , TDelegate<void(int32_t)> , etc.
    CantUseInScript=1<<13, //type can not use in script. such as TWeakObjectPtr<T> , TDelegate<T> , etc.
    ScriptInner=1<<14, //type is inner type in script. such as  Null ,int,CString, is Basic typs+Null
    Void = 1<<15, //type is void type.

    //some useful type,not necessary be a occupy a flag
    Optional=1<<20, //type is optional type. such as TOptional<int32_t> , TOptional<RObject> , etc.
    ForwardLinkedList=1<<21, //type is linked list type. such as TForwardForwardLinkedList<int32_t> , TForwardForwardLinkedList<RObject> , etc.
    Vector = 1<<22, //type is vector type. such as TVector<int32_t> , TVector<RObject> , etc.
    Map = 1<<23, //type is map type. such as TMap<int32_t,RObject> , TMap<RObject,RWidget> , etc.
    SubclassOf=1<<24, //type is subclass of type. such as RWidget is subclass of RObject, etc.
    Pair=1<<25, //type is pair type. such as TPair<int32_t,RObject> , TPair<RObject,RWidget> , etc.
    ScriptType=1<<26, //type is type of type. used in script. such as typeof(int32_t) , typeof(RObject) , etc.
    WidgetAttribute=1<<27, //type is widget attribute type. such as TWidgetAttribute<int>, etc.
};


//define operator | for ETypeFlags
inline ETypeFlags operator|(ETypeFlags A,ETypeFlags B)
{
    return static_cast<ETypeFlags>(static_cast<uint32_t>(A) | static_cast<uint32_t>(B));
}

//define operator & for ETypeFlags
inline ETypeFlags operator&(ETypeFlags A,ETypeFlags B)
{
    return static_cast<ETypeFlags>(static_cast<uint32_t>(A) & static_cast<uint32_t>(B));
}

//define operator ^ for ETypeFlags
inline ETypeFlags operator^(ETypeFlags A,ETypeFlags B)
{
    return static_cast<ETypeFlags>(static_cast<uint32_t>(A) ^ static_cast<uint32_t>(B));
}

//define operator ~ for ETypeFlags
inline ETypeFlags operator~(ETypeFlags A)
{
    return static_cast<ETypeFlags>(~static_cast<uint32_t>(A));
}

//define operator |= for ETypeFlags
inline ETypeFlags& operator|=(ETypeFlags& A,ETypeFlags B)
{
    A=static_cast<ETypeFlags>(static_cast<uint32_t>(A) | static_cast<uint32_t>(B));
    return A;
}

//define operator &= for ETypeFlags
inline ETypeFlags& operator&=(ETypeFlags& A,ETypeFlags B)
{
    A=static_cast<ETypeFlags>(static_cast<uint32_t>(A) & static_cast<uint32_t>(B));
    return A;
}

//define operator ^= for ETypeFlags
inline ETypeFlags& operator^=(ETypeFlags& A,ETypeFlags B)
{
    A=static_cast<ETypeFlags>(static_cast<uint32_t>(A) ^ static_cast<uint32_t>(B));
    return A;
}

//if A has B flag
inline bool HasFlag(ETypeFlags A,ETypeFlags B)
{
    return (A&B)==B;
}


class WHENGINE_API CType
{

public:
    /// @brief 
    /// @param InID 
    /// @param Name 
    /// @param InFlags 
    /// @param InParentNameScope Generialized type's parent name scope is global name scope
    CType(STypeID InID
        ,ETypeFlags InFlags
        );
    virtual ~CType();

    static CString GetEngineCoreNamespace(); 
    static CString GetEngineEditorNamespace();

        

    //CString GetName() const;

    //获得完整的名字，包括命名空间
    CString GetFullName() const;

    //获得短名字，不包括命名空间
    CString GetShortName() const;

    bool CanHaveInstance() const {return Instancable!=nullptr;}
    uint32_t GetSize() const ; //get size of this type's instance, in bytes,for pre-allocated memory
    void* CreateInstance(); //allocate and create instance of this type
    void InitInstance(void* Memory); //create instance of this type    
    void EraseInstance(void* Instance); //destroy instance of this type,but not free memory
    void* CloneInstance(const void* Instance) ; //allocate and clone instance of this type
    void CloneInstance(const void* Instance,void * TargetMemory); //clone instance of this type
    uint64_t GetInstanceHash(const void * Instance) const ; //get hash of instance of this type
    bool IsInstanceEqual(const void * Instance0,const void * Instance1) const; //compare instance of this type

    //reset value
    //erase and re-initialize memory for this type in script
    //require the instance is initialized
    void ResetAllocated(void* InInstance) ;

    bool IsForceConvertableTo(CType * Other);

    bool IsBasicType() const { return HasFlag(Flags,ETypeFlags::Basic); }
    bool IsVoidType() const { return HasFlag(Flags,ETypeFlags::Void); }
    //if return true ,can safely convert to CTVectorGeneralized
    bool IsVectorType() const { return HasFlag(Flags,ETypeFlags::Vector); }
    //if return true ,can safely convert to CPairGeneralized
    bool IsPairType()  const { return HasFlag(Flags,ETypeFlags::Pair); }
    bool IsForwardLinkedListType() const { return HasFlag(Flags,ETypeFlags::ForwardLinkedList); }
    bool IsMapType() const { return HasFlag(Flags,ETypeFlags::Map); }
    bool IsFunctionType()  const { return HasFlag(Flags,ETypeFlags::FunctionPointer); }
    bool IsSharedObjectPtrType() const {return HasFlag(Flags,ETypeFlags::SharedObjectPtr);}
    bool IsWeakObjectPtrType() const {return HasFlag(Flags,ETypeFlags::WeakObjectPtr);}
    bool IsWidgetAttributeType() const {return HasFlag(Flags,ETypeFlags::WidgetAttribute);}
    bool IsRawPointerType() const {return HasFlag(Flags,ETypeFlags::RawPointer);}
    bool IsOptionalType() const {return HasFlag(Flags,ETypeFlags::Optional);}
    bool IsSmartObjectPtr() const {return IsSharedObjectPtrType() || IsWeakObjectPtrType();}  
    bool IsSubclassOfType() const {return HasFlag(Flags,ETypeFlags::SubclassOf);}
    bool IsEnumType() const {return HasFlag(Flags,ETypeFlags::Enum);}
	bool IsClassType() const {return HasFlag(Flags,ETypeFlags::Class);}
    bool IsStructType() const {return HasFlag(Flags,ETypeFlags::Struct);}
    
    bool IsGenericType() const {return GenericInfo!=nullptr;}
    bool IsGeneralizedType() const {return GeneralizedInfo!=nullptr;}
    bool IsGenericPlaceholderType() const {return HasFlag(Flags,ETypeFlags::Placeholder);}
	bool IsListPlaceholderType() const;

    bool IsDelegateType() const {return HasFlag(Flags,ETypeFlags::Delegate);}

    //can serialize/deserialize to/from string
    //only provide Serialize method for basic type now
    bool IsStringSerializable() const {return StringSerializable!=nullptr;};
    CString SerializeToString(const void * Instance) const; //convert instance of this type to string
    void DeserializeFromString(const CString& String,void * Instance) const; //convert string to instance of this type


    // virtual bool IsDelegateTypeWith0Param() const {return false;}
    // virtual bool IsDelegateTypeWith1Param() const {return false;}
    // virtual bool IsDelegateTypeWith2Param() const {return false;}
    // virtual bool IsDelegateTypeWith3Param() const {return false;}
    // virtual bool IsDelegateTypeWith4Param() const {return false;}
    // virtual bool IsDelegateTypeWith5Param() const {return false;}
    // virtual bool IsDelegateTypeWith6Param() const {return false;}
    // virtual bool IsDelegateTypeWith7Param() const {return false;}

   
    //if return true ,can use in script
    //some type like TWeakObjectPtr<T> , can not use in script
    bool CanUseInScript() const {return !HasFlag(Flags,ETypeFlags::CantUseInScript);}

    bool IsValueTypeInScript() const { return !IsClassType(); }

    //is type defined in script
    bool IsScriptType() const { return HasFlag(Flags,ETypeFlags::Script); }
    bool IsScriptInnerType() const { return HasFlag(Flags,ETypeFlags::ScriptInner); }
    bool IsScriptClassType() const { return IsClassType() && IsScriptType(); }
    bool IsScriptStructType() const{ return IsStructType() && IsScriptType(); }

    bool IsScriptGenericStructType() const{ return IsScriptStructType() && IsGenericType(); }
    bool IsScriptGeneralizedStruct() const{ return IsScriptStructType() && IsGeneralizedType(); }
    bool IsScriptGeneralizedClasse() const{ return IsScriptClassType() && IsGeneralizedType(); }
    bool IsScriptGenericClassType() const{ return IsScriptClassType() && IsGenericType(); }

    //is value type in script
    //not means this type is create by script
    bool WasTreatAsValueTypeInScript() { return !IsSmartObjectPtr(); }

    
    CString ToDebugString(const void * Instance) const; //convert instance of this type to debug string
    int64_t GetDebugNamedChildNum(const void * Instance) const; //get number of named children value
    CType* GetDebugNamedChildType(int64_t Index,const void * Instance) const; //get type of named children value
    CString GetDebugNamedChildName(int64_t Index,const void * Instance) const ; //get name of named children value
    const void* GetDebugNamedChildValue(int64_t Index,const void * Instance) const; //get value of named children value
    int64_t GetDebugIndexedChildNum(const void * Instance) const; //get number of indexed children value
    CType* GetDebugIndexedChildType(int64_t Index,const void * Instance) const; //get type of indexed children value
    const void* GetDebugIndexedChildValue(int64_t Index,const void * Instance) const; //get value of indexed children value    

	STypeID ID;

    //CString Name;

    ETypeFlags Flags;

    //垃圾回收接口
    //如果该类型不参与垃圾回收，该指针为nullptr
    IGarbageCollectable* GarbageCollectable=nullptr;

    // might be null
    CFunctionList* Functions=nullptr;

    // might be null
    CPropertyList* Properties=nullptr;

    //if StringSerializable==nullptr, this type can not serialize to string
    IStringSerializable* StringSerializable=nullptr;

    //if Instancable==nullptr, this type can not have instance
    ITypeInstance* Instancable=nullptr;
    
    void SetBaseType(CType* InBaseType);

    // might be null
    CType* BaseType=nullptr;

    TVector<CType*> DerivedTypes;

    //fill this type's properties and functions
    //might be null
    std::function<void()> PostConstructFunction;

    //add dependent library
    //might be null
    //std::function<void()> PostConstructFunction2;

    //generic things,like TVector<T>, if GenericInfo is not null, GeneralizedInfo must be null
    CGenericInfo* GenericInfo=nullptr;
    //generalized things,like TVector<int>, if GeneralizedInfo is not null, GenericInfo must be null
    CGeneralizedInfo* GeneralizedInfo=nullptr;

    CPlaceholderInfo* PlaceholderInfo=nullptr;

	static TMap<CString /* class name */, CType*>& GetAllTypes();

	static CType* FindType(const CString& InTypeName);

	static CTypeTable& GetTypeTable();

	static CType* FindType(STypeID InTypeID);


    CProperty* FindProperty(const CString& InPropertyName);

    CNativeFieldProperty* FindNativeFieldPropertyByOffset(int64_t Offset);

    //return the first function with the given name
    CFunction* FindFunction(const CString& InFunctionName);

    //find function by native function pointer
    CFunction* FindNativeFunction(int64_t NativeFunctionPtr);

    //这个类型是否依赖于编辑器代码
    bool IsDependsOnEditor();
};


template<typename T>
class CGetType;

template<>
class WHENGINE_API CGetType<bool>
{
public:    
    CType* operator() ();
};

template<>
class WHENGINE_API CGetType<int64_t>
{
public:    
    CType* operator() ();
};

template<>
class WHENGINE_API CGetType<int32_t>
{
public:    
    CType* operator() ();
};

template<>
class WHENGINE_API CGetType<int16_t>
{
public:    
    CType* operator() ();
};

template<>
class WHENGINE_API CGetType<int8_t>
{
public:    
    CType* operator() ();
};

template<>
class WHENGINE_API CGetType<uint64_t>
{
public:    
    CType* operator() ();
};

template<>
class WHENGINE_API CGetType<uint32_t>
{
public:    
    CType* operator() ();
};


template<>
class WHENGINE_API CGetType<uint16_t>
{
public:    
    CType* operator() ();
};

template<>
class WHENGINE_API CGetType<uint8_t>
{
public:    
    CType* operator() ();
};


template<>
class WHENGINE_API CGetType<float>
{
public:    
    CType* operator() ();
};

template<>
class WHENGINE_API CGetType<double>
{
public:    
    CType* operator() ();
};

template<>
class WHENGINE_API CGetType<CString>
{
public:    
    CType* operator() ();
};

template<>
class WHENGINE_API CGetType<char32_t>
{
public:    
    CType* operator() ();
};

template<>
class WHENGINE_API CGetType<std::nullptr_t>
{
public:    
    CType* operator() ();
};

template<>
class WHENGINE_API CGetType<void>
{
public:    
    CType* operator() ();
};


